#include"ThreadCache.h"


//因为每一个线程都要自己的ThreadCache，所以不需要加锁
void* ThreadCache::Allocate(size_t size){
    assert(size<=256*1024);
    //计算需要分配的对齐数内存
    size_t alignsize=SizeClass::RoundUp(size);
    //找出对应的哈希桶
    int hashpos=SizeClass::Index(alignsize);
    assert(hashpos>=0&&hashpos<204);
    //自由链表为空，则先向下一层申请内存
    if(_lists[hashpos].Empty()){
        FetchFromCentralCache(hashpos,alignsize);
    }
    return _lists[hashpos].Pop();
}

//归还内存，obj归还的对象，size归还字节数
void ThreadCache::Deallocate(void* obj,size_t size){
    assert(size<=256*1024);
    //计算实际发配分配的对齐数内存
    size_t alignsize=SizeClass::RoundUp(size);
    //映射的哈希桶
    int hashpos=SizeClass::Index(alignsize);
    // if(hashpos<0||hashpos>204){
    //     //printf("对象大小size:%ld\n",alignsize);
    //     Span* p=PageCache::GetPageCache()->MapObjectToSpan(obj);
    // }
    assert(hashpos>=0&&hashpos<204);
    //将对象归还到对应的哈希桶中
    _lists[hashpos].Push(obj);
    //如果当前自由链表持有的对象大于向下一层获取的一批值时，则返回一批对象给下一层
    if(_lists[hashpos].Size()>=_lists[hashpos].MaxSize()){
        void*start=nullptr;
        void*end=nullptr;
        _lists[hashpos].PopRange(start,end,_lists[hashpos].MaxSize());
        //将对象归还给下一层
        CentralCache::GetInstance()->ReleaseListToSpans(start,alignsize);
    }
}

//这里既需要传递的是需要的对象个数（方便知道分配几个）也需要对象的大小（方便后续切割）
void ThreadCache::FetchFromCentralCache(int index,size_t alignsize){
    //通过start和end接收多个对象，方便后续链上自由链表
    void*start=nullptr;
    void*end=nullptr;
    //向下一层获取多少个对象,一次获取一个，可能会频繁向下层调用，获取多了，又会浪费空间
    //通过慢启动算法，防止一次获取太多对象，导致浪费空间
    int num=SizeClass::NumMoveSize(alignsize);
    int actualNum=num>_lists[index].MaxSize()?++_lists[index].MaxSize():num;
    //std::cout<<"actualNum:"<<actualNum<<std::endl;
    //单个对象的大小alignsize，以及需要多少个对象actualNum，
    size_t n=CentralCache::GetInstance()->FetchRangeObj(start,end,actualNum,alignsize);
    //std::cout<<"n:"<<n<<std::endl;
    _lists[index].PushRange(start,end,n);
}

//线程存储局部变量，确保每一个线程都拥有一个ThreadCache
//thread_local ThreadCache* pTLSThreadCache=nullptr;